package cn.codenest;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * create by: Hyman
 * description: AIO是指异步IO的缩写，NIO的IO行为还是同步的，而AIO不是在IO准备好时再通知线程，而是调用一个回调函数
 * create time: 2021/4/26
 */
public class Server {

    public final static int PORT = 8003;

    private AsynchronousServerSocketChannel server;

    public Server() throws IOException {
        server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(PORT));
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        Server server = new Server();
        server.start();
        while (true){
            Thread.sleep(1000);
        }
    }

    public void start() {
        System.out.println("Server listen on " + PORT);
        //注册事件和事件完成后的处理器
        /*1、accept()方法会立即返回
         * 2、第一个参数是附件，可以是任意类型，作用是当前线程和后续的回调方法可以共享信息，它会在后续的调用中传递给handler
         * 3、accept()实际做了两件事：第一是告诉系统可以开始监听端口了；第二，注册CompletionHandler实例，告诉系统一旦有客户端来连接，
         * 如果连接成功，就去执行completed方法
         * */
        server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {

            final ByteBuffer buffer = ByteBuffer.allocate(1024);

            /**
             * create by: Hyman
             * description:
             * 1、result是客户端的连接channel
             * create time: 2021/4/26
             */
            @Override
            public void completed(AsynchronousSocketChannel result, Object attachment) {
                System.out.println(Thread.currentThread().getName());
                Future<Integer> writeResult = null;
                buffer.clear();
                try {
                    result.read(buffer).get(100, TimeUnit.SECONDS);
                    buffer.flip();
                    /*write是一个异步方法，返回Future对象*/
                    writeResult = result.write(buffer);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                } finally {
                    /*这里需要再次使server进入监听状态*/
                    server.accept(null, this);
                    try {
                        /*阻塞等待写入结果*/
                        writeResult.get();
                        /*关闭套接字*/
                        result.close();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }

            @Override
            public void failed(Throwable exc, Object attachment) {
                System.out.println("failed: " + exc);
            }
        });
    }
}
